package middleware

import (
	"github.com/dgrijalva/jwt-go"
	"github.com/kataras/iris/v12"
	"github.com/kataras/iris/v12/sessions"
	"iristest/common/log"
	"iristest/common/res"
	"strconv"
	"time"
)

//需要继承 ctx.User{}接口才能将信息存放在 ctx.User里

type TokenInfo struct {
	AppId    int64
	UserId   int64
	Username string
	jwt.StandardClaims
}

func (ti TokenInfo) GetRaw() (interface{}, error) {
	return &ti, nil
}
func (ti TokenInfo) GetAuthorization() (string, error) {
	return "", nil
}
func (ti TokenInfo) GetAuthorizedAt() (time.Time, error) {
	return time.Time{}, nil
}
func (ti TokenInfo) GetID() (string, error) {
	return strconv.FormatInt(ti.UserId, 10), nil
}
func (ti TokenInfo) GetUsername() (string, error) {
	return ti.Username, nil
}
func (ti TokenInfo) GetPassword() (string, error) {
	return "", nil
}
func (ti TokenInfo) GetEmail() (string, error) {
	return "", nil
}
func (ti TokenInfo) GetRoles() ([]string, error) {
	return nil, nil
}
func (ti TokenInfo) GetToken() ([]byte, error) {
	return nil, nil
}
func (ti TokenInfo) GetField(key string) (interface{}, error) {
	return nil, nil
}

var (
	//自定义的token密钥
	secret = []byte("heiy1234567890")
	//该路由下不效验token
	noVerify = []string{"/login", "/ping", "/register"}
	//token有效时间(纳秒)
	effectTime = 2 * time.Hour
)

//生成token
func GenerateToken(ti *TokenInfo) string {
	//设置token有效期
	ti.ExpiresAt = time.Now().Add(effectTime).Unix()
	//生成token
	sign, err := jwt.NewWithClaims(jwt.SigningMethodHS256, ti).SignedString(secret)
	if err != nil {
		log.Err(err, "生成token失败")
		return ""
	}
	return sign
}

//验证token
func JwtVerify(ctx iris.Context) {
	//过滤是否验证token
	if filter(noVerify, ctx.Path()) {
		ctx.Next()
		return
	}
	//从sessions中找token,没找到再从请求头里找
	token := sessions.Get(ctx).Get("token")
	//token := ctx.GetHeader("token")
	if token == nil {
		token = ctx.GetHeader("token")
		if token == "" || token == "null" {
			ctx.Write(res.NoLogin().JsonToBytes())
			return
		}
	}
	ctx.SetUser(parseToken(token.(string)))
	ctx.Next()
}

//解析token
func parseToken(tokenStr string) *TokenInfo {
	token, err := jwt.ParseWithClaims(tokenStr, &TokenInfo{}, func(token *jwt.Token) (interface{}, error) {
		return secret, nil
	})
	if err != nil {
		log.Err(err, "解析token失败,token:", tokenStr)
		return nil
	}
	claims, ok := token.Claims.(*TokenInfo)
	if !ok {
		log.Ex("token is valid")
		return nil
	}
	return claims
}

func filter(ls []string, url string) bool {
	urlCount := len(url)
	for _, l := range ls {
		count := urlCount - len(l)

		if count >= 0 && l == url[count:] {
			return true
		}
	}
	return false
}
